package com.turbo.cloud.ums.web.logic;

import cn.hutool.core.util.StrUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.turbo.cloud.core.exception.BusinessException;
import com.turbo.cloud.core.utils.BeanListUtils;
import com.turbo.cloud.core.security.utils.SecurityUtil;
import com.turbo.cloud.ums.constants.UMSConstants;
import com.turbo.cloud.ums.utils.vuemenu.VueMenuUtil;
import com.turbo.cloud.ums.utils.vuemenu.VueMenu;
import com.turbo.cloud.ums.web.entity.UmsMenu;
import com.turbo.cloud.ums.web.entity.UmsPermissionMenuRelation;
import com.turbo.cloud.ums.web.model.menu.UmsMenuQO;
import com.turbo.cloud.ums.web.model.menu.UmsMenuDO;
import com.turbo.cloud.ums.web.model.menu.UmsMenuVO;
import com.turbo.cloud.ums.utils.MenuTreeUtil;
import com.turbo.cloud.ums.web.service.IUmsMenuService;
import com.turbo.cloud.ums.web.service.IUmsPermissionMenuRelationService;
import com.turbo.cloud.ums.web.service.IUmsRolePermissionRelationService;
import com.turbo.cloud.ums.web.service.IUmsUserRoleRelationService;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.BeanUtils;
import org.springframework.stereotype.Component;
import org.springframework.transaction.annotation.Transactional;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.Objects;

/**
 * <p>
 * 菜单表 逻辑处理类
 * </p>
 *
 * @author zhangluning
 * @since 2022-08-13
 */
@Slf4j
@RequiredArgsConstructor
@Component
public class MenuLogic {

    final IUmsMenuService umsMenuService;
    final IUmsUserRoleRelationService umsUserRoleRelationService;
    final IUmsRolePermissionRelationService umsRolePermissionRelationService;
    final IUmsPermissionMenuRelationService umsPermissionMenuRelationService;

    /**
     * 权限类型：0->目录；1->菜单；2->按钮；3->接口
     */
    final static Integer[] MENU_TYPE_GROUP_MENU_ARR = {0, 1};
    final static Integer MENU_TYPE_CONTROL = 2;

    /**
     * 根据当前系统ID，查询菜单树列表
     *
     * @return TreeList
     */
    public List<UmsMenuVO> queryMenuTreeList() {
        // 获取菜单一维列表
        LambdaQueryWrapper<UmsMenu> menuLQW = new LambdaQueryWrapper<>();
        menuLQW.eq(UmsMenu::getSystemId, SecurityUtil.getCurrentSystemId());
        menuLQW.in(UmsMenu::getType, Arrays.asList(MENU_TYPE_GROUP_MENU_ARR));
        menuLQW.orderByAsc(UmsMenu::getSort);

        List<UmsMenu> menuList = umsMenuService.list(menuLQW);

        // 菜单一维列表转树
        List<UmsMenuVO> menuTreeList = MenuTreeUtil.toMenuTree(menuList);
        return menuTreeList;
    }

    /**
     * 根据当前系统ID，标记权限选中的菜单树
     *
     * @return TreeList
     */
    public List<UmsMenuVO> queryMenuCheckedTreeListOfPermissionId(UmsMenuQO umsMenuQO) {
        LambdaQueryWrapper<UmsMenu> menuLQW = new LambdaQueryWrapper<>();
        menuLQW.eq(UmsMenu::getSystemId, SecurityUtil.getCurrentSystemId());
        menuLQW.in(UmsMenu::getType, Arrays.asList(MENU_TYPE_GROUP_MENU_ARR));
        menuLQW.orderByAsc(UmsMenu::getSort);

        List<UmsMenu> menuList = umsMenuService.list(menuLQW);

        List<String> menuIdsByRole = new ArrayList<>();
        if (StrUtil.isNotBlank(umsMenuQO.getPermissionId())) {
            LambdaQueryWrapper<UmsPermissionMenuRelation> roleMenuRelationLQW = new LambdaQueryWrapper<>();
            roleMenuRelationLQW.eq(UmsPermissionMenuRelation::getPermissionId, umsMenuQO.getPermissionId());
            List<UmsPermissionMenuRelation> roleMenuListByRoleId = umsPermissionMenuRelationService.list(roleMenuRelationLQW);

            menuIdsByRole = roleMenuListByRoleId.stream().map(UmsPermissionMenuRelation::getMenuId).toList();
        }
        List<UmsMenuVO> menuTreeList = MenuTreeUtil.toMenuCheckedTree(menuList, menuIdsByRole);
        return menuTreeList;
    }

    /**
     * 根据权限ID获取关联菜单树
     *
     * @return TreeList
     */
    public List<UmsMenuVO> queryCheckedMenuTreeListByPermissionId(UmsMenuQO umsMenuQO) {
        LambdaQueryWrapper<UmsMenu> menuLQW = new LambdaQueryWrapper<>();
        menuLQW.eq(UmsMenu::getSystemId, SecurityUtil.getCurrentSystemId());
        menuLQW.in(UmsMenu::getType, Arrays.asList(MENU_TYPE_GROUP_MENU_ARR));
        menuLQW.orderByAsc(UmsMenu::getSort);

        List<UmsMenu> menuList = umsMenuService.list(menuLQW);

        LambdaQueryWrapper<UmsPermissionMenuRelation> roleMenuRelationLQW = new LambdaQueryWrapper<>();
        roleMenuRelationLQW.eq(UmsPermissionMenuRelation::getPermissionId, umsMenuQO.getPermissionId());
        List<UmsPermissionMenuRelation> roleMenuListByRoleId = umsPermissionMenuRelationService.list(roleMenuRelationLQW);

        List<String> menuIdsByRole = roleMenuListByRoleId.stream().map(UmsPermissionMenuRelation::getMenuId).toList();

        List<UmsMenuVO> menuTreeList = MenuTreeUtil.toCheckedMenuTree(menuList, menuIdsByRole);
        return menuTreeList;
    }

    /**
     * 查询登录人的菜单树列表
     *
     * @return TreeList
     */
    public List<UmsMenuVO> queryMenuTreeByCurrentUser() {
        List<UmsMenu> menuList = queryMenuListByCurrentUserId();
        List<UmsMenuVO> menuTreeList = MenuTreeUtil.toMenuTree(menuList);
        return menuTreeList;
    }

    /**
     * 查询登录人的菜单Vue格式树列表
     *
     * @return TreeList
     */
    public List<VueMenu> queryVueMenuTreeByCurrentUser() {
        List<UmsMenu> menuList = queryMenuListByCurrentUserId();
        List<UmsMenuVO> menuVOList = new ArrayList<>();
        BeanListUtils.copyList(menuList, menuVOList, UmsMenuVO::new);

        return VueMenuUtil.toVueMenuTreeList(menuVOList);
    }

    /**
     * 查询登录人的菜单列表
     *
     * @return TreeList
     */
    public List<UmsMenuVO> queryMenuListByCurrentUser() {
        List<UmsMenu> menuList = queryMenuListByCurrentUserId();
        List<UmsMenuVO> menuVOList = new ArrayList<>();
        BeanListUtils.copyList(menuList, menuVOList, UmsMenuVO::new);
        return menuVOList;
    }


    /**
     * 查询登录人的菜单列表
     *
     * @return TreeList
     */
    public List<VueMenu> queryVueMenuListByCurrentUser() {
        List<UmsMenu> menuList = queryMenuListByCurrentUserId();
        List<UmsMenuVO> menuVOList = new ArrayList<>();
        BeanListUtils.copyList(menuList, menuVOList, UmsMenuVO::new);

        return VueMenuUtil.toSimpleVueMenuList(menuVOList);
    }

    /**
     * 根据用户对应角色权限和菜单ID查询授权的菜单ID列表
     *
     * @return
     */
    public List<UmsMenu> queryMenuListByCurrentUserId() {

        /*
         * 获取当前用户的权限的菜单ID
         */
        LambdaQueryWrapper<UmsPermissionMenuRelation> roleMenuRelationLQW = new LambdaQueryWrapper();
        roleMenuRelationLQW.in(UmsPermissionMenuRelation::getPermissionId, SecurityUtil.getCurrentUserPermissions());
        List<UmsPermissionMenuRelation> roleMenuRelationList = umsPermissionMenuRelationService.list(roleMenuRelationLQW);

        List<String> menuIds = roleMenuRelationList.stream().map(UmsPermissionMenuRelation::getMenuId).toList();
        if (Objects.isNull(menuIds) || menuIds.isEmpty()) {
            throw new BusinessException("当前用户的角色未关联菜单");
        }

        /*
         * 获取当前用户的角色的菜单
         */
        LambdaQueryWrapper<UmsMenu> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(UmsMenu::getSystemId, SecurityUtil.getCurrentSystemId());
        List<UmsMenu> menuListSource = umsMenuService.list(queryWrapper);

        List<String> menuParentIds = MenuTreeUtil.getParentIds(menuListSource, menuIds);
        List<String> roleMenuIds = new ArrayList<>();
        roleMenuIds.addAll(menuIds);
        roleMenuIds.addAll(menuParentIds);

        queryWrapper.in(UmsMenu::getId, roleMenuIds);
        List<Integer> types = Arrays.asList(MENU_TYPE_GROUP_MENU_ARR);
        queryWrapper.in(UmsMenu::getType, types);
        queryWrapper.orderByAsc(UmsMenu::getSort);
        List<UmsMenu> menuList = umsMenuService.list(queryWrapper);

        return menuList;
    }

    /**
     * 获取单个菜单
     *
     * @param id 菜单ID
     * @return
     */
    public UmsMenuVO queryMenuById(String id) {
        UmsMenu resultTmp = umsMenuService.getById(id);
        UmsMenuVO result = new UmsMenuVO();
        BeanUtils.copyProperties(resultTmp, result);
        return result;
    }

    /**
     * 新增菜单
     *
     * @param umsMenuDO 实体
     * @return
     */
    public Boolean createMenu(UmsMenuDO umsMenuDO) {
        if (StrUtil.isBlank(umsMenuDO.getSystemId())) {
            String systemId = SecurityUtil.getCurrentSystemId();
            umsMenuDO.setSystemId(systemId);
        }

        UmsMenu umsMenu = new UmsMenu();
        BeanUtils.copyProperties(umsMenuDO, umsMenu);

        boolean result = umsMenuService.save(umsMenu);
        if (!result) {
            throw new BusinessException("新增菜单失败");
        }
        return true;
    }

    /**
     * 修改菜单
     *
     * @param umsMenuDO 实体
     * @return
     */
    public Boolean modifyMenu(UmsMenuDO umsMenuDO) {
        if (StrUtil.isBlank(umsMenuDO.getId())) {
            throw new BusinessException("菜单ID不能为空");
        }
        UmsMenu umsMenu = new UmsMenu();
        BeanUtils.copyProperties(umsMenuDO, umsMenu);

        boolean result = umsMenuService.updateById(umsMenu);
        if (!result) {
            throw new BusinessException("修改菜单失败");
        }
        return true;
    }

    /**
     * 开启、关闭菜单有效状态
     *
     * @param id 权限ID
     * @return
     */
    @Transactional(rollbackFor = Exception.class)
    public boolean enabledMenuStateById(String id) {
        UmsMenu umsMenu = umsMenuService.getById(id);
        if (Objects.isNull(umsMenu)) {
            throw new BusinessException("菜单不存在");
        }

        if (UMSConstants.DICT_STATE_ID_YES.equals(umsMenu.getStateId())) {
            umsMenu.setStateId(0);
        } else {
            umsMenu.setStateId(1);
        }

        boolean result = umsMenuService.updateById(umsMenu);
        if (!result) {
            throw new BusinessException("修改菜单状态失败");
        }
        return true;
    }

    /**
     * 删除菜单
     *
     * @param id 菜单ID
     * @return
     */
    public boolean removeMenuById(String id) {
        if (StrUtil.isBlank(id)) {
            throw new BusinessException("菜单ID不能为空");
        }

        boolean result = umsMenuService.removeById(id);
        if (!result) {
            throw new BusinessException("修改菜单失败");
        }
        return true;
    }
}
